#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include"Cond.hpp"
#include"Mutex.hpp"

static int gcap = 10;


namespace BlockQueueModule
{
	using namespace CondModule;
	using namespace LockModule;


	template<typename T> 
	class BlockQueue
	{
	private:
		bool IsFull() {return _q.size() == _cap;}
		bool IsEmpty() {return _q.empty();}

	public:
		BlockQueue(int cap = gcap):_cap(cap),_cwait_num(0),_pwait_num(0)
		{}


		// 生产者
		void Equeue(const T& in)
		{
			LockGuard lockguard(_mutex);

			while(IsFull())
			{
				std::cout << "生产者进入等待..." << std::endl;
				_pwait_num++;

				_productor_cond.Wait(_mutex);

				_pwait_num--;
				std::cout << "生产者被唤醒" << std::endl;
			}

			_q.push(in);

			if(_cwait_num)
			{
				std::cout << "消费者被叫醒" << std::endl;
				
				_consumer_cond.Noticy();
			}
		}


		// 消费者
		void Pop(T* out)
		{
			LockGuard lockguard(_mutex);
			while(IsEmpty())  
			{
				std::cout << "消费者进入等待..." << std::endl;
				_cwait_num++;
				
				_consumer_cond.Wait(_mutex);

				_cwait_num--;
				std::cout << "消费者被唤醒" << std::endl;
			}

			*out = _q.front();
			_q.pop();

			if(_pwait_num)
			{
				std::cout << "生产者被叫醒" << std::endl;
				_productor_cond.Noticy();
			}
		}

		~BlockQueue()
		{}

	private:
		std::queue<T> _q;               //保存数据的容器--临界资源
		int _cap;                        //bq最大容量
		Mutex _mutex;			//互斥锁
		Cond _productor_cond; //生产者条件变量
		Cond _consumer_cond;  //消费者条件变量

		int _cwait_num;                 //等待的消费者数量
		int _pwait_num;					//等待的生产者数量
	};
}